-------------Guitar Wizard-------------
A 4am crack                  2018-04-07
---------------------------------------

Name: Guitar Wizard
Version: "GW 11601"
Genre: sound
Year: 1986
Publisher: Baudville
Platform: Apple ][+ or later (64K)
Media: 5.25-inch disk
Sides: 1
OS: custom
Similar cracks:
  #68 Blazing Paddles

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


COPYA
  no errors, but copy prints version
  number on screen then grinds the disk
  in a most unusual fashion (hopping
  back and forth between two tracks)
  until I frantically power off in an
  attempt to save my 35-year-old floppy
  drive from frog-stepping off my desk

Locksmith Fast Disk Backup
  ditto

EDD 4 bit copy (no sync, no count)
  ditto

Copy ][+ nibble editor
  nothing suspicious

Disk Fixer
  T00 -> custom bootloader
  T11 -> DOS 3.3 disk catalog
  T04-05 -> possibly a copy of DOS 3.3
  (for example, DOS error strings on
  T05,S02)

Why didn't any of my copies work?
  probably a protection check in the
  custom bootloader

Next steps:

  1. Trace the boot
  2. Disable the protection check
  3. Declare victory (*)

(*) Go to the gym

                   ~

               Chapter 1
         Boot Trace and Chill


[S6,D1=original disk]
[S5,D1=my work disk]

]PR#5
...

]CALL -151

*9600<C600.C6FFM

; copy boot sector to higher memory so
; it survives a reboot
96F8-   A0 00       LDY   #$00
96FA-   B9 00 08    LDA   $0800,Y
96FD-   99 00 28    STA   $2800,Y
9700-   C8          INY
9701-   D0 F7       BNE   $96FA

; turn off the slot 6 drive motor
9703-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9706-   4C 00 C5    JMP   $C500

*BSAVE TRACE0,A$9600,L$109
*9600G
...reboots slot 6...
...reboots slot 5...

; save captured boot sector
]BSAVE OBJ.0800-08FF,A$2800,L$100
]CALL -151

; move it back into place
*800<2800.28FFM

*801L

; starts off looking like a DOS 3.3
; bootloader
0801-   A5 27       LDA   $27
0803-   C9 09       CMP   #$09
0805-   D0 34       BNE   $083B
0807-   A5 2B       LDA   $2B
0809-   4A          LSR
080A-   4A          LSR
080B-   4A          LSR
080C-   4A          LSR
080D-   09 C0       ORA   #$C0
080F-   85 3F       STA   $3F
0811-   A9 5C       LDA   #$5C
0813-   85 3E       STA   $3E
0815-   18          CLC

; slightly unusual -- it appears to
; keep the target address and sector
; count in $0866/7 instead of $08FE/F
0816-   AD 66 08    LDA   $0866
0819-   6D 67 08    ADC   $0867
081C-   8D 66 08    STA   $0866

; enable read/write on RAM bank 2 (at
; $D000..$FFFF)
081F-   AD 83 C0    LDA   $C083
0822-   AD 83 C0    LDA   $C083

; set low-level reset vector
0825-   A9 EF       LDA   #$EF
0827-   8D FC FF    STA   $FFFC
082A-   8D FE FF    STA   $FFFE
082D-   8D FA FF    STA   $FFFA
0830-   A9 08       LDA   #$08
0832-   8D FD FF    STA   $FFFD
0835-   8D FF FF    STA   $FFFF
0838-   8D FB FF    STA   $FFFB

; looks like a sector read loop
083B-   AE 67 08    LDX   $0867

; jump out of the read loop here
083E-   30 28       BMI   $0868
0840-   BD 55 08    LDA   $0855,X
0843-   85 3D       STA   $3D
0845-   CE 67 08    DEC   $0867
0848-   AD 66 08    LDA   $0866
084B-   85 27       STA   $27
084D-   CE 66 08    DEC   $0866
0850-   A6 2B       LDX   $2B

; jump to disk controller ROM routine
; to read sectors
0852-   6C 3E 00    JMP   ($003E)
.
.
.
; looks like the loop above will read
; 7 sectors into $DA00..$E0FF
0866-   DA
0867-   07

Execution continues from $0868 (from
the BMI at $083E).

*868L

; out of the sector read loop --
; switch back to ROM, initialize
; keyboard/video/text mode/screen
0868-   AD 82 C0    LDA   $C082
086B-   20 93 FE    JSR   $FE93
086E-   20 89 FE    JSR   $FE89
0871-   20 2F FB    JSR   $FB2F
0874-   20 58 FC    JSR   $FC58

0877-   A0 00       LDY   #$00
0879-   20 A5 08    JSR   $08A5

*8A5L

; display the version number
08A5-   B9 B7 08    LDA   $08B7,Y
08A8-   85 24       STA   $24
08AA-   C8          INY
08AB-   B9 B7 08    LDA   $08B7,Y
08AE-   F0 06       BEQ   $08B6
08B0-   20 F0 FD    JSR   $FDF0
08B3-   4C AA 08    JMP   $08AA
08B6-   60          RTS

(This prints "GW 11601".)

; check for Applesoft in ROM, display
; error if not found (not shown)
087C-   AD 00 E0    LDA   $E000
087F-   C9 4C       CMP   #$4C
0881-   D0 13       BNE   $0896

; switch back to RAM bank 2
0883-   AD 83 C0    LDA   $C083
0886-   AD 83 C0    LDA   $C083

; push ($E000) to the stack, then
; "return" to that address (+1)
0889-   AD 00 E0    LDA   $E000
088C-   C9 E0       CMP   #$E0
088E-   D0 06       BNE   $0896
0890-   48          PHA
0891-   AD 01 E0    LDA   $E001
0894-   48          PHA
0895-   60          RTS

And that's where I get to interrupt the
boot.

                   ~

               Chapter 2
         Time Is A Flat Circle
        And So Is A Floppy Disk


*9600<C600.C6FFM

; Interrupt boot at $0868, immediately
; after the sector read loop exits. Set
; up a callback to a routine under my
; control so I can capture the code in
; RAM bank 2.
96F8-   A9 4C       LDA   #$4C
96FA-   8D 68 08    STA   $0868
96FD-   A9 0A       LDA   #$0A
96FF-   8D 69 08    STA   $0869
9702-   A9 97       LDA   #$97
9704-   8D 6A 08    STA   $086A

; start the boot
9707-   4C 01 08    JMP   $0801

; callback is here -- copy $DA00..$E0FF
; to main memory so it will survive a
; reboot (RAM bank 2 is read/write at
; this point)
970A-   A2 07       LDX   #$07
970C-   A0 00       LDY   #$00
970E-   B9 00 DA    LDA   $DA00,Y
9711-   99 00 2A    STA   $2A00,Y
9714-   C8          INY
9715-   D0 F7       BNE   $970E
9717-   EE 10 97    INC   $9710
971A-   EE 13 97    INC   $9713
971D-   CA          DEX
971E-   D0 EE       BNE   $970E

; switch back from RAM bank 2 to ROM
9720-   AD 82 C0    LDA   $C082

; turn off slot 6 drive motor
9723-   AD E8 C0    LDA   $C0E8

; reboot to my work disk
9726-   4C 00 C5    JMP   $C500

*BSAVE TRACE1,A$9600,L$129

*9600G
...reboots slot 6...
...reboots slot 5...

]BSAVE OBJ.DA00-E0FF,A$2A00,L$700
]CALL -151

(The code at $DA00..$E0FF is loaded in
$2A00..$30FF, so everything is off by
$B000. Relative branches will look
correct, but absolute addresses will
be off by $B000.)

First, let's see what would be at $E000
and $E001, which the boot0 code pushes
to the stack.

*3000.3001

3000- E0 02

OK, so execution continues at $E003
(the address pushed to the stack, +1).

*3003L

; seek to track 0
3003-   A6 2B       LDX   $2B
3005-   A9 00       LDA   #$00
3007-   20 A0 DC    JSR   $DCA0

; read the next available address field
300A-   20 44 DC    JSR   $DC44

; Zero page $2D is part of the scratch
; space used by the RWTS to verify the
; address field checksum. (The routine
; is at $B962..$B98A in a regular DOS
; 3.3 RWTS. Zero page $2F holds the
; disk volume number; $2E holds the
; track number; $2D holds the sector
; number; $2C holds the checksum. This
; RWTS is in RAM bank 2 but apparently
; uses the same zero page addresses.)
300D-   A5 2D       LDA   $2D
300F-   C9 00       CMP   #$00

; keep reading address fields until we
; find sector 0
3011-   D0 F7       BNE   $300A

; wait loop (not shown, always waits
; the same amount of time)
3013-   20 BF E0    JSR   $E0BF

; now seek to next track
3016-   A0 01       LDY   #$01
3018-   8C CD E0    STY   $E0CD
301B-   98          TYA
301C-   0A          ASL
301D-   20 A0 DC    JSR   $DCA0

; and read the address field of the
; next available sector (without any
; regard for which sector it is)
3020-   20 44 DC    JSR   $DC44

; and wait again
3023-   20 BF E0    JSR   $E0BF

; now compare the sector number we
; actually found to a predetermined
; list of expected sector numbers)
3026-   A5 2D       LDA   $2D
3028-   AC CD E0    LDY   $E0CD
302B-   D9 CE E0    CMP   $E0CE,Y

; if we didn't find the "right" sector,
; jump back to the beginning and start
; again (which explains why my copy
; makes that unique grinding sound)
302E-   D0 D5       BNE   $3005

; if we did find the right sector, loop
; back and advance to the next track
; (up to track 8)
3030-   C8          INY
3031-   C0 08       CPY   #$08
3033-   90 E3       BCC   $3018

; seek back to track 0
3035-   A9 00       LDA   #$00
3037-   20 A0 DC    JSR   $DCA0

; the rest of this looks like normal
; initialization of the RWTS parameter
; table (albeit shifted)
303A-   A5 2B       LDA   $2B
303C-   8D D0 DF    STA   $DFD0
303F-   8D DE DF    STA   $DFDE
3042-   8D F2 DF    STA   $DFF2
3045-   4A          LSR
3046-   4A          LSR
3047-   4A          LSR
3048-   4A          LSR
3049-   AA          TAX
304A-   A9 00       LDA   #$00
304C-   8D 79 DD    STA   $DD79
304F-   0A          ASL
3050-   9D 79 DD    STA   $DD79,X
3053-   A9 01       LDA   #$01
3055-   8D DF DF    STA   $DFDF
3058-   8D D1 DF    STA   $DFD1
.
.
.     ; array of expected sectors
30CF-   05 0A 0F 04 09 0E 03 08
30D7-   0D 02 07 0C 01 06 0B 00

That is a fascinating form of copy
protection. It requires multiple tracks
to be synchronized on the physical disk
in such a way that blindly jumping
between the tracks finds sectors in a
specific order as the disk is rotating
in the drive. It's theoretically
possible to defeat -- the "sync tracks"
option in bit copiers was designed for
this -- but it was finicky and highly
reliant on the speed of your floppy
drive.

Anyway, this copy protection routine
doesn't seem to have any side effects.
If it succeeds, execution continues at
$E03A. If it fails, it keeps trying
until it succeeds (or until it destroys
your disk drive).

I can change the branch at $E02E to
continue to the next instruction, and
the protection routine will eventually
exit as if it found the correct sectors
on each track.

T00,S06,$2F: D5 -> 00

]PR#6
...works...

Quod erat liberandum.

                   ~

            Acknowledgments


Thanks to LoGo for the original disk.

---------------------------------------
A 4am crack                    No. 1734
------------------EOF------------------
